package com.new1cloud.file.tools;

import com.new1cloud.file.upload.client.entry.ChunkFile;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import lombok.Cleanup;
import lombok.SneakyThrows;

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Objects;

/**
 * 文件分片工具类
 */
public class FileSlicerTool {

    /**
     * 文件分片
     * @param ctx 上下文
     * @param sourceFilePath 文件路径
     * @param position 偏移量
     * @param chunkSize 分片大小，单位字节
     * @param chunkFile 分片文件对象
     * @return 已被设置分片数据的分片文件对象
     */
    @SneakyThrows
    public static ChunkFile gotChunkFileBytes(ChannelHandlerContext ctx, String sourceFilePath, Long position, Long chunkSize, ChunkFile chunkFile) {
        @Cleanup RandomAccessFile file = new RandomAccessFile(sourceFilePath, "r");
        @Cleanup FileChannel channel = file.getChannel();
        final long fileSize = channel.size();
        if(position >= fileSize) {
            return chunkFile;
        }

//        channel.position(position);
        // 计算当前切片的结束位置，防止超过文件末尾
        long limit = Math.min(position + chunkSize, fileSize);
        long readSize = limit - position;
//        // 创建FileRegion
//        FileRegion region = new DefaultFileRegion(channel, position, readSize);
        // 映射当前切片（关闭 `FileChannel` 和 `RandomAccessFile`，它们会自动关闭关联的 `MappedByteBuffer`）
        MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, position, readSize);
        // 创建一个字节数组来存储切片数据
        byte[] sliceData = new byte[(int) (readSize)];
        // 将映射的缓冲区数据复制到字节数组中
        buffer.get(sliceData);
        chunkFile.setChunkData(sliceData);

        return chunkFile;
    }

    /**
     * 基于ByteBuf的文件分片
     */
    @SneakyThrows
    public static ChunkFile chunkFileByteBuf(ChannelHandlerContext ctx, String sourceFilePath, Long position, Long chunkSize, ChunkFile chunkFile) {
        @Cleanup RandomAccessFile file = new RandomAccessFile(sourceFilePath, "r");
        @Cleanup FileChannel channel = file.getChannel();
        final long fileSize = channel.size();
        if(position >= fileSize) {
            return chunkFile;
        }

        // 计算当前切片的结束位置，防止超过文件末尾
        long limit = Math.min(position + chunkSize, fileSize);
        long readSize = limit - position;
        ByteBuf buf = ctx.alloc().buffer((int) readSize);
        int index = position.intValue();

        channel.read(buf.internalNioBuffer(index, (int) readSize));
        buf.readerIndex(Objects.equals(0, index) ? 0 : index + 1);
        chunkFile.setChunkData(null);
        return chunkFile;
    }

    /**
     * 将byte[]转化为ByteBuf
     * @param ctx ctx
     * @param array byte[]
     * @return ByteBuf
     */
    public static ByteBuf convertByteArrayToByteBuf(ChannelHandlerContext ctx, byte[] array) {
        // 1. 获取ByteBufAllocator
        ByteBufAllocator allocator = ctx.alloc();
        // 2. 使用ByteBufAllocator创建ByteBuf
        ByteBuf byteBuf = allocator.buffer();
        // 3. 将byte[]写入ByteBuf
        byteBuf.writeBytes(array);
        return byteBuf;
    }
}
